{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 这个程序用来实现机器学习 HW1 作业5 要求的线性回归，对要求的三十个数据进行拟合。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 初始化设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始设置\n",
    "import numpy as np\n",
    "import random\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(30,)\n",
      "(30,)\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 导入数据, 不对数据进行初始化\n",
    "def load_data(filename):\n",
    "    X = []\n",
    "    y = []\n",
    "    with open(filename, 'r') as f:\n",
    "        for line in f:\n",
    "            xi, yi = line.strip('\\n').split('\\t',1) \n",
    "            X.append(float(xi))\n",
    "            y.append(float(yi))\n",
    "    X = np.array(X)\n",
    "    y = np.array(y)\n",
    "    return X, y\n",
    "    \n",
    "filename = 'data'\n",
    "X, y = load_data(filename)\n",
    "print(np.shape(X))\n",
    "print(np.shape(y))\n",
    "# 数据可视化\n",
    "plt.scatter(X, y)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 损失函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# MSE 损失函数\n",
    "def MSE_Loss(X, y):\n",
    "    '''\n",
    "    Computing the MSE loss.\n",
    "    Input:\n",
    "        - X: predictions. N x 1\n",
    "        - y: ground truth. N x 1\n",
    "    Output:\n",
    "        - Loss: the loss.\n",
    "        - dout: the gradient of X.\n",
    "    '''\n",
    "    N = X.shape[0]\n",
    "    Loss = 0.5 * np.dot(X - y, X - y) / N\n",
    "    dout = (X - y) / N\n",
    "    return Loss, dout"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.5\n",
      "[ 0.   0.  -0.5  0. ]\n"
     ]
    }
   ],
   "source": [
    "# 使用这个来测试 MSE_Loss 是否正确\n",
    "a = np.array([1,1,1,1])\n",
    "b = np.array([1,1,3,1])\n",
    "Loss, dout = MSE_Loss(a, b)\n",
    "print(Loss)\n",
    "print(dout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 两个模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 线性回归模型1 \n",
    "class model_1(object):\n",
    "    '''\n",
    "    The model is y = w0 + w1*x\n",
    "    '''\n",
    "    def __init__(self, w, lr=0.1, mini_batch=5):\n",
    "        self.w = w\n",
    "        self.lr = lr\n",
    "        self.batch = mini_batch\n",
    "        self.loss = []\n",
    "    \n",
    "    def train(self, X, y, num=50):\n",
    "        '''\n",
    "        Utilize SGD to learning the parameters.\n",
    "        Input:\n",
    "            - X: the input data. N x 1\n",
    "            - y: the labels of the data. N x 1\n",
    "            - num: the iteration number.\n",
    "        '''\n",
    "        N = X.shape[0]\n",
    "        index = random.sample(range(1,N), self.batch)\n",
    "        X_train = X[index]\n",
    "        y_train = y[index]\n",
    "        for i in range(num):\n",
    "            out, cache = self.forward(X_train)\n",
    "            Loss, dout = MSE_Loss(out, y_train)\n",
    "            dw, dx = self.backward(cache, dout)\n",
    "            self.w = self.w - self.lr * dw\n",
    "            self.loss.append(Loss)\n",
    "    \n",
    "    def forward(self, X):\n",
    "        '''\n",
    "        Computing the prediction.\n",
    "        Input: \n",
    "            - X: the input data. N x 1\n",
    "        Ouput:\n",
    "            - y: the prediction. N x 1\n",
    "            - cache: cache X to compute the gradient\n",
    "        '''\n",
    "        N = X.shape[0]\n",
    "        X = np.c_[np.ones(N), X]\n",
    "        y = np.dot(X, self.w)\n",
    "        cache = X\n",
    "        return y, cache\n",
    "    \n",
    "    def backward(self, cache, dout):\n",
    "        '''\n",
    "        Computing the gradient.\n",
    "        Input:\n",
    "            - dout: the gradient flow from upstream. N x 1\n",
    "        Output:\n",
    "            - dw: the gradient of w. D x 1\n",
    "            - dX: the gradient of X. N x D\n",
    "        '''\n",
    "        X = cache\n",
    "        dw = np.dot(X.T,dout)\n",
    "        dx = None # This gradient is useless, if have time will complete it.\n",
    "        return dw, dx\n",
    "    \n",
    "    def loss_history(self):\n",
    "        return self.loss\n",
    "    \n",
    "    def get_weight(self):\n",
    "        return self.w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The equation of fitting curve is: y = w_0 + w_1 * x\n",
      "weight: (w_0, w_1) = [1.00654209 0.41458616]\n",
      "The final MSE Loss is: 0.003626268364367745\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 参数初始化\n",
    "batch = 15 # batch_size of SGD\n",
    "learning_rate = 1e-1 # 初始化步长\n",
    "weight = 0.02 * np.random.randn(2) # 权重初始化\n",
    "iteration = 1000 # 迭代次数\n",
    "\n",
    "p1 = model_1(weight, lr=learning_rate, mini_batch=batch)\n",
    "p1.train(X,y,iteration)\n",
    "pred_y, cache = p1.forward(X)\n",
    "Loss, dout = MSE_Loss(pred_y, y)\n",
    "print('The equation of fitting curve is: y = w_0 + w_1 * x')\n",
    "print('weight: (w_0, w_1) = %s' % p1.get_weight())\n",
    "print('The final MSE Loss is: %s' % p1.loss_history()[-1])\n",
    "\n",
    "# training loss\n",
    "plt.figure()\n",
    "plt.title('Training loss')\n",
    "plt.plot(p1.loss_history(),'o')\n",
    "plt.xlabel('Iteration')\n",
    "plt.show()\n",
    "\n",
    "# 数据可视化\n",
    "plt.figure()\n",
    "plt.title('Visualize')\n",
    "plt.plot(X,y,'o')\n",
    "x = np.linspace(-1,1,200)\n",
    "pred_y, cache = p1.forward(x)\n",
    "plt.plot(x,pred_y)\n",
    "plt.ylabel('y')\n",
    "plt.xlabel('x')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 线性回归模型2\n",
    "class model_2(object):\n",
    "    '''\n",
    "    The model is y = w0 + w1*x\n",
    "    '''\n",
    "    def __init__(self, w, lr=0.1, mini_batch=5):\n",
    "        self.w = w\n",
    "        self.lr = lr\n",
    "        self.batch = mini_batch\n",
    "        self.loss = []\n",
    "    \n",
    "    def train(self, X, y, num=50,weight_decay=0.99):\n",
    "        '''\n",
    "        Utilize SGD to learning the parameters.\n",
    "        Input:\n",
    "            - X: the input data. N x 1\n",
    "            - y: the labels of the data. N x 1\n",
    "            - num: the iteration number.\n",
    "        '''\n",
    "        N = X.shape[0]\n",
    "        index = random.sample(range(1,N), self.batch)\n",
    "        X_train = X[index]\n",
    "        y_train = y[index]\n",
    "        for i in range(num):\n",
    "            out, cache = self.forward(X_train)\n",
    "            Loss, dout = MSE_Loss(out, y_train)\n",
    "            dw, dx = self.backward(cache, dout)\n",
    "            self.w = self.w - self.lr * dw * weight_decay \n",
    "            self.loss.append(Loss)\n",
    "    \n",
    "    def forward(self, X):\n",
    "        '''\n",
    "        Computing the prediction.\n",
    "        Input: \n",
    "            - X: the input data. N x 1\n",
    "        Ouput:\n",
    "            - y: the prediction. N x 1\n",
    "            - cache: cache X to compute the gradient\n",
    "        '''\n",
    "        N = X.shape[0]\n",
    "        X = np.c_[np.ones(N), X, X * X]\n",
    "        y = np.dot(X, self.w)\n",
    "        cache = X\n",
    "        return y, cache\n",
    "    \n",
    "    def backward(self, cache, dout):\n",
    "        '''\n",
    "        Computing the gradient.\n",
    "        Input:\n",
    "            - dout: the gradient flow from upstream.\n",
    "        Output:\n",
    "            - dw: the gradient of w.\n",
    "            - dx: the gradient of x.\n",
    "        '''\n",
    "        X = cache\n",
    "        dw = np.dot(X.T,dout)\n",
    "        dx = None # This gradient is useless, if have time will complete it.\n",
    "        return dw, dx\n",
    "    \n",
    "    def loss_history(self):\n",
    "        return self.loss\n",
    "    \n",
    "    def get_weight(self):\n",
    "        return self.w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the equation of fitting curve is: y = w_0 + w_1 * x + w_2 * x^2\n",
      "weight = (w_0, w_1, w_2) =  [0.89849935 0.37734644 0.08957233] \n",
      "The final MSE Loss is: 0.0017936767581843318\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 参数初始化\n",
    "batch = 5 # batch_size of SGD\n",
    "learning_rate = 1e-1 # 初始化步长\n",
    "weight = 0.02 * np.random.randn(3) # 权重初始化 \n",
    "iteration = 5000# 迭代次数\n",
    "\n",
    "p2 = model_2(weight, lr=learning_rate, mini_batch=batch)\n",
    "p2.train(X,y,iteration,weight_decay=0.99)\n",
    "pred_y, cache = p2.forward(X)\n",
    "Loss, dout = MSE_Loss(pred_y, y)\n",
    "print('the equation of fitting curve is: y = w_0 + w_1 * x + w_2 * x^2')\n",
    "print('weight = (w_0, w_1, w_2) =  %s ' % p2.get_weight())\n",
    "print('The final MSE Loss is: %s' % p2.loss_history()[-1])\n",
    "\n",
    "# training loss\n",
    "plt.figure()\n",
    "plt.title('Training loss')\n",
    "plt.plot(p2.loss_history(),'o')\n",
    "plt.xlabel('Iteration')\n",
    "plt.show()\n",
    "\n",
    "# 数据可视化\n",
    "plt.figure()\n",
    "plt.title('Visualize')\n",
    "plt.plot(X,y,'o')\n",
    "x = np.linspace(-1,1,200)\n",
    "pred_y, cache = p2.forward(x)\n",
    "plt.plot(x,pred_y)\n",
    "plt.ylabel('y')\n",
    "plt.xlabel('x')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 总结：从上面的实验中我们可以得到，对于这组数据在使用梯度下降 500 个 iteration 后，两者最终的 MSE loss 相差不大，都可以比较好的拟合曲线。但是不同的是使用一次函数进行梯度下降的时候解比较稳定，而使用二次曲线进行拟合的时候解不稳定，经常会出现过拟合的情况，可以考虑增加数据或者加入正则项减弱这个情况。从 Loss 曲线上看，两者很快就进入了梯度消失，所以如果我们期望更多的学习，我们可以考虑使用 BN 或者其他的方法缓解梯度消失问题。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "torch",
   "language": "python",
   "name": "torch"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
